Skip to content

Presentation Drafts In Any Environment, Plus Blog And UI Review Fixes - #431

Merged
anshroboto merged 10 commits into
mainfrom
fix/presentation-visual-editing-in-production
Aug 5, 2026
Merged

Presentation Drafts In Any Environment, Plus Blog And UI Review Fixes#431
anshroboto merged 10 commits into
mainfrom
fix/presentation-visual-editing-in-production

Conversation

@anshroboto

@anshroboto anshroboto commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Problem / Intent

Draft mode was gated to NODE_ENV === "development", so the deployed Studio's Presentation tool could never preview the live site — <VisualEditing /> never mounted, <SanityLive> only ever listened for published content, and no stega was emitted, leaving Presentation with "No matching documents". Alongside that, a review pass turned up four unrelated defects: blog pagination kept the previous page on screen during soft navigation, out-of-range pages returned 200, hover treatments used three different colour pairs, and code blocks rendered their code in a different typeface from their line numbers.

This branch gates draft rendering on the request's session rather than the environment, and fixes the four review items.

Summary

  • Presentation now works against any deployment. Drafts render for a request carrying a draft-mode session, which only /api/presentation-draft can mint (it validates a Sanity preview secret). Anonymous requests still resolve to published content, so / stays statically prerendered and missing routes still return real 404s.
  • Blog pagination re-suspends on soft navigation. The Suspense boundary is now keyed on page + category; without a key React reconciled it as the same boundary and kept the previous page's posts and pager mounted for the whole server round trip — the URL read ?page=2 while the grid still showed page 1.
  • Out-of-range blog pages 404. ?page=3 on a two-page blog previously returned 200 with an empty list.
  • One hover treatment across nav, FAQ and blog cards — zinc-100 in light, zinc-900 in dark. Nav previously hardcoded zinc-200/zinc-800 in three files and the shared utility used zinc-800.
  • Code blocks render in one typeface. Tailwind Preflight styled bare code with the default mono stack, overriding the family inherited from <pre>, so line numbers and code used different fonts and metrics.
  • Footer social icons fade on hover instead of painting a solid tile behind the icon.
  • Browser tabs show the page title only, without the site-name suffix; the site name moves to Open Graph siteName.

Core file changes

File Change
packages/sanity/src/live.ts DRAFT_MODE_ENABLEDDRAFTS_WITHOUT_SESSION; getDynamicFetchOptions now reads draftMode() first and only falls back to published when there is no session
apps/web/src/app/layout.tsx <SanityLive> and the Presentation overlay moved into a Suspense-isolated LivePreviewLayer, so reading draftMode() cannot opt the whole layout out of prerendering
apps/web/src/app/page.tsx, [...slug]/page.tsx, blog/[slug]/page.tsx Branch on isDraftMode || DRAFTS_WITHOUT_SESSION instead of the environment, keeping the published fast path and real notFound() for everyone else
apps/web/src/app/blog/page.tsx Keyed inner Suspense boundary; parseBlogPageParam; assertBlogPageInRange called from generateMetadata so an out-of-range page 404s before the status is committed
packages/ui/src/styles/globals.css hover-surface dark hover zinc-800 → zinc-900; .rich-code gains shared inset variables, inherited line-height and a two-digit gutter min-width
packages/sanity-blocks/src/internal/code-block.tsx font-mono on <code> so the utilities layer beats Preflight
packages/sanity-blocks/src/faq-accordion/index.tsx Resting surface back to bg-background so the new hover is visible; duration-300animation-duration-300 so the entrance no longer stretches the hover fade
apps/web/src/components/navbar.tsx, mobile-menu.tsx, elements/menu-link.tsx Hardcoded hover:bg-zinc-200 dark:hover:bg-zinc-800 replaced with the shared hover-surface utility
apps/web/src/components/footer.tsx Social icons drop the solid hover tile for an opacity fade
apps/web/src/lib/seo.ts Page title only, no site-name suffix; siteName added to openGraph

Verification

  • pnpm check-types — 8/8
  • pnpm lint — 9/9
  • pnpm format:check — 9/9
  • pnpm test — 213 tests, 26 files
  • pnpm build:web/ still ○ (Static); /[...slug], /blog, /blog/[slug] still ◐ (Partial Prerender)
  • Anonymous production request to a missing route returns a real 404, not a soft one
  • /api/presentation-draft returns 401 with no secret and with a bogus secret
  • On /blog, click "Next page" — the grid and the pager both move to page 2. A/B against an instrumented build: unkeyed held page 1 for 4081ms with the pager stuck on "1"; keyed drops to 41ms and shows the skeleton
  • /blog?page=3 returns 404 for a crawler user-agent
  • Hover a nav link, an FAQ item and a blog card in both themes — all resolve to #f4f4f5 light / #18181b dark

Summary by CodeRabbit

  • New Features
    • Improved draft and live preview behavior, including reliable production preview sessions.
    • Added smoother navigation transitions as visitors approach the end of a page.
  • Bug Fixes
    • Published pages and blog posts now return accurate 404 pages when content is unavailable.
    • Blog navigation validates page numbers and categories to prevent invalid content displays.
  • Improvements
    • Updated metadata and refined navigation, menus, footer, FAQ, code styling, dark-mode hover states, and reduced-motion support.

@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
turbo-start-sanity Ready Ready Preview Aug 5, 2026 10:24am

Request Review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 25 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7ba12420-05a4-4ee2-b96b-56c236a4329f

📥 Commits

Reviewing files that changed from the base of the PR and between 9ed6fd8 and de7cd37.

📒 Files selected for processing (1)
  • packages/ui/src/styles/globals.css
📝 Walkthrough

Walkthrough

The update adds request-time draft rendering, session-aware Sanity fetch options, stricter blog pagination validation, keyed blog navigation boundaries, shared hover and code-block styling, FAQ animation changes, and revised SEO metadata.

Changes

Draft rendering and live preview

Layer / File(s) Summary
Session-aware Sanity fetch options
packages/sanity/src/live.ts
Sanity fetch options now select draft content for active sessions or development requests without sessions. Other requests use published content.
Request-time draft route selection
apps/web/src/app/page.tsx, apps/web/src/app/[...slug]/page.tsx, apps/web/src/app/blog/[slug]/page.tsx
Routes read draftMode() and select draft-aware or cached published rendering. Published paths return real 404 responses for missing content.
Suspended live preview layout
apps/web/src/app/layout.tsx
LivePreviewLayer reads draft state inside Suspense and configures SanityLive, PreviewBar, and VisualEditing.

Blog pagination validation

Layer / File(s) Summary
Blog page validation and metadata
apps/web/src/app/blog/page.tsx
Metadata and content rendering reject malformed, non-positive, and out-of-range pages with notFound(). Count request errors continue through normal error handling.
Keyed blog navigation refresh
apps/web/src/app/blog/page.tsx
The blog Suspense boundary is keyed by category and page.

Presentation and metadata

Layer / File(s) Summary
Shared hover and navigation styling
packages/ui/src/styles/globals.css, apps/web/src/components/elements/menu-link.tsx, apps/web/src/components/mobile-menu.tsx, apps/web/src/components/navbar.tsx, apps/web/src/components/footer.tsx
Navigation uses hover-surface, the navbar uses nav-exit, and footer icons use opacity transitions.
Content display styling
packages/sanity-blocks/src/faq-accordion/index.tsx, packages/sanity-blocks/src/internal/code-block.tsx, packages/ui/src/styles/globals.css
FAQ timing, code font styling, rich-code padding, and gutter sizing are updated.
SEO metadata composition
apps/web/src/lib/seo.ts
Page titles use only the resolved title. Open Graph metadata includes siteName.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Possibly related PRs

Suggested reviewers: voidhrithik, sameerroboto

Poem

A rabbit checks the draft-mode gate,
Pages choose their rendered state.
Blog paths reject invalid ones,
Fresh boundaries replace old runs.
Hover shades and code align,
Metadata stays in line.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main draft-rendering change and accurately identifies the related blog and UI fixes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/presentation-visual-editing-in-production

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/app/layout.tsx (1)

50-76: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Render draft navigation and footer for a valid draft session.

When a production Presentation session is active, showDrafts remains false because it only reads DRAFTS_WITHOUT_SESSION. The page routes render drafts for the same session, but CachedNavbar and CachedFooter still render published navigation, footer, and settings.

Move the navbar/footer selection into a Suspense-contained request-time layer. Select dynamic content when draftMode().isEnabled || DRAFTS_WITHOUT_SESSION is true. This preserves the static anonymous layout and makes the Presentation view consistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/app/layout.tsx` around lines 50 - 76, Update the layout’s navbar
and footer selection around showDrafts, CachedNavbar, and CachedFooter by moving
the request-time draft-mode check into a Suspense-contained layer. Use dynamic
navigation and footer when draftMode().isEnabled or DRAFTS_WITHOUT_SESSION is
true; otherwise retain the cached published components, preserving the static
anonymous layout.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@apps/web/src/app/layout.tsx`:
- Around line 50-76: Update the layout’s navbar and footer selection around
showDrafts, CachedNavbar, and CachedFooter by moving the request-time draft-mode
check into a Suspense-contained layer. Use dynamic navigation and footer when
draftMode().isEnabled or DRAFTS_WITHOUT_SESSION is true; otherwise retain the
cached published components, preserving the static anonymous layout.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0e6a4ed6-adb6-42ee-8a60-be5afee3beee

📥 Commits

Reviewing files that changed from the base of the PR and between 0ae4a20 and 79b3bd3.

📒 Files selected for processing (14)
  • apps/web/src/app/[...slug]/page.tsx
  • apps/web/src/app/blog/[slug]/page.tsx
  • apps/web/src/app/blog/page.tsx
  • apps/web/src/app/layout.tsx
  • apps/web/src/app/page.tsx
  • apps/web/src/components/elements/menu-link.tsx
  • apps/web/src/components/footer.tsx
  • apps/web/src/components/mobile-menu.tsx
  • apps/web/src/components/navbar.tsx
  • apps/web/src/lib/seo.ts
  • packages/sanity-blocks/src/faq-accordion/index.tsx
  • packages/sanity-blocks/src/internal/code-block.tsx
  • packages/sanity/src/live.ts
  • packages/ui/src/styles/globals.css

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ui/src/styles/globals.css`:
- Line 291: Update the scroll-driven navbar animation’s animation-duration
declaration from auto to 1ms in the relevant globals.css rule. Keep the existing
scroll timeline and other animation properties unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 05330171-a79a-47a1-9e90-92919ac35a77

📥 Commits

Reviewing files that changed from the base of the PR and between 79b3bd3 and e9e46dc.

📒 Files selected for processing (2)
  • apps/web/src/components/navbar.tsx
  • packages/ui/src/styles/globals.css

Comment thread packages/ui/src/styles/globals.css Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ui/src/styles/globals.css`:
- Around line 301-303: Update the linting configuration for the nested `@supports`
block inside the `@utility` definition, specifically adjusting
no-invalid-position-declaration and the Sonar configuration to accept this valid
pattern. Preserve animation-name: nav-exit unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 251a151f-10ef-438f-b419-7b272054efff

📥 Commits

Reviewing files that changed from the base of the PR and between e9e46dc and 9ed6fd8.

📒 Files selected for processing (1)
  • packages/ui/src/styles/globals.css

Comment thread packages/ui/src/styles/globals.css Outdated
@anshroboto
anshroboto force-pushed the fix/presentation-visual-editing-in-production branch from 7937114 to de7cd37 Compare August 5, 2026 10:23
@sonarqubecloud

sonarqubecloud Bot commented Aug 5, 2026

Copy link
Copy Markdown

@anshroboto
anshroboto merged commit ce66fbf into main Aug 5, 2026
9 checks passed
@anshroboto
anshroboto deleted the fix/presentation-visual-editing-in-production branch August 5, 2026 10:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants